using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using ImpromptuInterface;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Builders;

namespace MongoDB.Dynamic
{
    public abstract class DynamicCollectionBase
    {
        protected readonly bool NotifyEnabled;
        protected string KeyName;
        protected Type KeyType;
        protected bool Audit;

        /// <summary>
        /// Cache property that will be used to eager load collections.
        /// </summary>
        internal MethodInfo CollectionQueryMethodInfo;

        /// <summary>
        /// Cache property that will be used to eager load foreignKeys
        /// </summary>

        internal MethodInfo GetByKeyMethodInfo;


        internal readonly MongoCollection<DynamicDocument> Collection;

        internal readonly Dictionary<string, DynamicCollectionBase> FkCollections
            = new Dictionary<string, DynamicCollectionBase>();

        internal readonly Dictionary<string, DynamicCollectionBase> ChildCollections
            = new Dictionary<string, DynamicCollectionBase>();

        protected readonly List<string> DocumentKeys = new List<string>();

        protected DynamicCollectionBase(string collectionName, string keyName = null, bool notifyEnabled = false, bool audit = false)
        {
            NotifyEnabled = notifyEnabled;
            Collection = Dynamic.Db.GetCollection<DynamicDocument>(collectionName);
            KeyName = keyName;
            this.Audit = audit;
        }

        public long Count()
        {
            return Collection.Count();
        }

        internal DynamicDocument GetBsonDocumentById(object id)
        {
            var dynamicDocument = Collection.FindOneById(BsonValue.Create(id));
            return dynamicDocument;
        }

        protected virtual void Update(object entity, object keyValue)
        {
            DynamicDocument doc = BuildDocument(entity, keyValue);
            Collection.Save(doc);
        }

        internal DynamicDocument BuildDocument(object entity, object id)
        {
            var document = new DynamicDocument(id, Audit);
            foreach (var name in DocumentKeys)
            {
                var pValue = Impromptu.InvokeGet(entity, name);
                try
                {
                    var bsonValue = BsonValue.Create(pValue);
                    document[name] = bsonValue;
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    document[name] = BsonNull.Value;
                    continue;
                }
            }

            return document;
        }

        protected static bool IsDefaultValue(object keyValue)
        {
            if (keyValue == null)
                return true;

            var bsonValue = BsonValue.Create(keyValue);

            switch (bsonValue.BsonType)
            {
                case BsonType.Int32:
                    return Convert.ToInt32(keyValue) == 0;
                default:
                    return false;
            }
        }

        /// <summary>
        /// Try delete a document from collection based on _id value.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool DeleteByKey(object key)
        {
            var result = Collection.FindAndRemove(Query.EQ("_id", BsonValue.Create(key)), SortBy.Null);
            return result.Ok;
        }
    }
}